/*
 * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Test startGc builtin.
 */
import { assert, newWeakRefInYoung } from 'common.abc';

// allocate an object of size in bytes at least 'sizeInBytes'
function allocLargeObject() {
    // Ctor Array(length) doesn't allocates the internal JSTaggedValue array.
    // Only length setter does this.
    let big = new Array();
    for (let i = 0; i < 60; ++i) {
        let a = allocateArrayObject(1024 * 8);
        if (i % 2 == 0) {
            big[i] = a;
        }
        if (i % 10 == 0) {
            startGC("young");
        }
    }
    return big;
}

function makeTenuredCollectible()
{
    // G1GC allocates a region in tenured space and moves objects to the region.
    // The region is not subject to collect till it get full.`
    // So we need to fill it up by moving more objects to this region.
    // When the region gets filled GC allocates a new region and the old region
    // can be collected.
    let tmp = allocLargeObject();
    startGC("young");
}

function newWeakRefInCollectibleTenured() {
    let obj = new Object();
    startGC("young"); // promote obj from young to tenured
    makeTenuredCollectible();
    return new WeakRef(obj);
}

// test young GC
let ref = newWeakRefInYoung();
let gc = startGC("young");
assert(ref.deref() === undefined, "Young GC didn't collect weak ref");
assert(gc === 0, "startGc for young should return 0");
// Check waitForFinishGC works with special values
waitForFinishGC(0);
let task_discarded_id = -1;
waitForFinishGC(task_discarded_id);

// test mixed GC
ref = newWeakRefInCollectibleTenured();
// Add more garbage objects and trigger concurrent marking
// to add garbage regions into collection set
makeTenuredCollectible();
waitForFinishGC(startGC("threshold"));
gc = startGC("mixed");
waitForFinishGC(gc);
assert(ref.deref() === undefined, "Mixed GC didn't collect weak ref");

// test full GC
ref = newWeakRefInCollectibleTenured();
let ref2 = newWeakRefInYoung();
gc = startGC("full");
waitForFinishGC(gc);
assert(ref.deref() === undefined, "Full GC didn't collect weak ref in tenured");
assert(ref2.deref() === undefined, "Full GC didn't collect weak ref in young");
